package com.qinglei.recoup.common.service.impl;

import com.alibaba.fastjson.JSON;
import com.aliyun.iot20180120.models.CreateOTAStaticUpgradeJobRequest;
import com.aliyun.iot20180120.models.CreateOTAStaticUpgradeJobResponse;
import com.aliyun.iot20180120.models.ListOTAFirmwareRequest;
import com.aliyun.iot20180120.models.ListOTAFirmwareResponse;
import com.aliyun.iot20180120.models.ListOTAModuleVersionsByDeviceRequest;
import com.aliyun.iot20180120.models.ListOTAModuleVersionsByDeviceResponse;
import com.aliyun.iot20180120.models.ListOTATaskByJobRequest;
import com.aliyun.iot20180120.models.ListOTATaskByJobResponse;
import com.aliyun.iot20180120.models.QueryOTAJobRequest;
import com.aliyun.iot20180120.models.QueryOTAJobResponse;
import com.aliyun.iot20180120.models.*;
import com.aliyun.teaopenapi.models.Config;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.iot.model.v20180120.GetDeviceStatusRequest;
import com.aliyuncs.iot.model.v20180120.GetDeviceStatusResponse;
import com.aliyuncs.iot.model.v20180120.QueryDevicePropertyStatusRequest;
import com.aliyuncs.iot.model.v20180120.QueryDevicePropertyStatusResponse;
import com.aliyuncs.iot.model.v20180120.QueryProductListRequest;
import com.aliyuncs.iot.model.v20180120.QueryProductListResponse;
import com.aliyuncs.iot.model.v20180120.SetDevicePropertyRequest;
import com.aliyuncs.iot.model.v20180120.SetDevicePropertyResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.gson.Gson;
import com.qinglei.recoup.common.domain.IotDeviceInfo;
import com.qinglei.recoup.common.exception.RedisConnectException;
import com.qinglei.recoup.common.properties.IotProperties;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.common.utils.JsonUtils;
import com.qinglei.recoup.system.pojo.QueryProduct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ProductCache {

    @Autowired
    private IotProperties iotProperties;

    @Autowired
    private RedisService redisService;


    public void cacheProduct() {
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", iotProperties.getAccessKey(), iotProperties.getAccessSecret());
        /** use STS Token
         DefaultProfile profile = DefaultProfile.getProfile(
         "<your-region-id>",           // The region ID
         "<your-access-key-id>",       // The AccessKey ID of the RAM account
         "<your-access-key-secret>",   // The AccessKey Secret of the RAM account
         "<your-sts-token>");          // STS Token
         **/
        IAcsClient client = new DefaultAcsClient(profile);

        QueryProductListRequest request = new QueryProductListRequest();
        request.setIotInstanceId("iot-010a0axp");
        request.setPageSize(200);
        request.setCurrentPage(1);

        try {
            QueryProductListResponse response = client.getAcsResponse(request);
            JsonNode node = JsonUtils.stringToJson(new Gson().toJson(response));
            String nodes = node.get("data").get("list").toString();
            redisService.set("product", nodes);
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            System.out.println("ErrCode:" + e.getErrCode());
            System.out.println("ErrMsg:" + e.getErrMsg());
            System.out.println("RequestId:" + e.getRequestId());
        } catch (RedisConnectException e) {
            e.printStackTrace();
        }
    }


    public boolean isExistEquipment(String snCode) throws RedisConnectException {
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", iotProperties.getAccessKey(), iotProperties.getAccessSecret());
        /** use STS Token
         DefaultProfile profile = DefaultProfile.getProfile(
         "<your-region-id>",           // The region ID
         "<your-access-key-id>",       // The AccessKey ID of the RAM account
         "<your-access-key-secret>",   // The AccessKey Secret of the RAM account
         "<your-sts-token>");          // STS Token
         **/
        IAcsClient client = new DefaultAcsClient(profile);

        GetDeviceStatusRequest request = new GetDeviceStatusRequest();
        request.setIotInstanceId("iot-010a0axp");
        request.setDeviceName(snCode);

        List<QueryProduct> queryProducts = JsonUtils.jsonToList(redisService.get("product"), QueryProduct.class);
        for (int i = 0; i < queryProducts.size(); i++) {
            String productKey = queryProducts.get(i).getProductKey();
            request.setProductKey(productKey);
            try {
                GetDeviceStatusResponse response = client.getAcsResponse(request);
                JsonNode jsonNode = JsonUtils.stringToJson(new Gson().toJson(response)).get("success");
                boolean s = Boolean.valueOf(jsonNode.toString());
                if (s) {
                    return true;
                }
            } catch (ServerException e) {
                e.printStackTrace();
            } catch (ClientException e) {
                System.out.println("ErrCode:" + e.getErrCode());
                System.out.println("ErrMsg:" + e.getErrMsg());
                System.out.println("RequestId:" + e.getRequestId());
            }
        }

        return false;
    }


    public Map<String, Object> isExistEquipmentProducts(String snCode) throws RedisConnectException {
        Map<String, Object> result = new HashMap<>();
        boolean isExistEquipment = false;
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", iotProperties.getAccessKey(), iotProperties.getAccessSecret());
        /** use STS Token
         DefaultProfile profile = DefaultProfile.getProfile(
         "<your-region-id>",           // The region ID
         "<your-access-key-id>",       // The AccessKey ID of the RAM account
         "<your-access-key-secret>",   // The AccessKey Secret of the RAM account
         "<your-sts-token>");          // STS Token
         **/
        IAcsClient client = new DefaultAcsClient(profile);

        GetDeviceStatusRequest request = new GetDeviceStatusRequest();
        request.setIotInstanceId("iot-010a0axp");
        request.setDeviceName(snCode);

        List<QueryProduct> queryProducts = JsonUtils.jsonToList(redisService.get("product"), QueryProduct.class);
        for (int i = 0; i < queryProducts.size(); i++) {
            String productKey = queryProducts.get(i).getProductKey();
            request.setProductKey(productKey);
            try {
                GetDeviceStatusResponse response = client.getAcsResponse(request);
                JsonNode jsonNode = JsonUtils.stringToJson(new Gson().toJson(response)).get("success");
                boolean s = Boolean.valueOf(jsonNode.toString());
                if (s) {
                    isExistEquipment = true;
                    result.put("productKey", productKey);
                }
            } catch (ServerException e) {
                e.printStackTrace();
            } catch (ClientException e) {
                System.out.println("ErrCode:" + e.getErrCode());
                System.out.println("ErrMsg:" + e.getErrMsg());
                System.out.println("RequestId:" + e.getRequestId());
            }
        }
        result.put("isExistEquipment", isExistEquipment);
        return result;
    }

    /**
     * 通过sn码，即设备名称去物联网平台查询设备是否存在，存在则返回设备信息，否则返回null
     *
     * @param snCode
     * @return
     */
    public IotDeviceInfo findDeviceBySn(String snCode) throws RedisConnectException {
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", iotProperties.getAccessKey(), iotProperties.getAccessSecret());
        /** use STS Token
         DefaultProfile profile = DefaultProfile.getProfile(
         "<your-region-id>",           // The region ID
         "<your-access-key-id>",       // The AccessKey ID of the RAM account
         "<your-access-key-secret>",   // The AccessKey Secret of the RAM account
         "<your-sts-token>");          // STS Token
         **/
        IAcsClient client = new DefaultAcsClient(profile);

        GetDeviceStatusRequest request = new GetDeviceStatusRequest();
        request.setIotInstanceId("iot-010a0axp");
        request.setDeviceName(snCode);

        IotDeviceInfo iotDeviceInfo = null;
        List<QueryProduct> queryProducts = JsonUtils.jsonToList(redisService.get("product"), QueryProduct.class);
        for (int i = 0; i < queryProducts.size(); i++) {
            String productKey = queryProducts.get(i).getProductKey();
            request.setProductKey(productKey);
            try {
                GetDeviceStatusResponse response = client.getAcsResponse(request);
                JsonNode jsonNode = JsonUtils.stringToJson(new Gson().toJson(response)).get("success");
                boolean s = Boolean.valueOf(jsonNode.toString());
                if (s) {
                    iotDeviceInfo = new IotDeviceInfo();
                    iotDeviceInfo.setSn(snCode);
                    iotDeviceInfo.setProductKey(productKey);
                    return iotDeviceInfo;
                }
            } catch (Exception e) {
                log.error("findDeviceBySn snCode:{},productKey:{}", snCode, productKey, e);
            }
        }

        return null;
    }
    /**
     * 跌倒设备获取设备属性快照（V4版本）
     *
     * @param snCode
     * @param productKey
     * @return Map key-属性标识，value-属性值
     */
    public Map<String, String> getDevicePropertyStatus(String snCode, String productKey) {
        return this.getDevicePropertyStatus(snCode,productKey,null);
    }
    /**
     * 获取设备属性快照（V4版本）
     *
     * @param snCode
     * @param productKey
     * @return Map key-属性标识，value-属性值
     */
    public Map<String, String> getDevicePropertyStatus(String snCode, String productKey,String functionBlockId) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", iotProperties.getAccessKey(), iotProperties.getAccessSecret());
        IAcsClient client = new DefaultAcsClient(profile);
        QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();
        request.setIotInstanceId("iot-010a0axp");
        request.setDeviceName(snCode);
        request.setProductKey(productKey);
        if(StringUtils.isNotEmpty(functionBlockId)){
            request.setFunctionBlockId(functionBlockId);
        }
        log.info("QueryDevicePropertyStatusRequest,deviceName:{},productKey:{}", snCode, productKey);
        try {
            QueryDevicePropertyStatusResponse response = client.getAcsResponse(request);
            log.info("QueryDevicePropertyStatusResponse:{}", JsonUtils.objectToJson(response));
            if (!response.getSuccess()) {
                log.warn("getDevicePropertyStatus failed, snCode:{},productKey:{},code:{}, message:{}", snCode, productKey, response.getCode(), response.getErrorMessage());
                return null;
            }
            if (response.getData() == null || response.getData().getList() == null) {
                log.warn("getDevicePropertyStatus data is null, snCode:{},productKey:{}", snCode, productKey);
                return null;
            }
            Map<String, String> retMap = new HashMap<>();
            for (QueryDevicePropertyStatusResponse.Data.PropertyStatusInfo propertyStatusInfo : response.getData().getList()) {
                retMap.put(propertyStatusInfo.getIdentifier(), propertyStatusInfo.getValue());
            }
            log.debug("getDevicePropertyStatus return:{}", retMap);
            return retMap;
        } catch (ClientException e) {
            log.error("getDeviceShadow snCode:{}", snCode, e);
        }
//        log.info("getDevicePropertyStatus return:null");
        return null;
    }

    /**
     * 设置设备属性（V4版本）
     *
     * @param snCode
     * @param productKey
     * @param items
     * @return
     */
    public boolean setDevicePropertyStatus(String snCode, String productKey, Map<String, Object> items) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", iotProperties.getAccessKey(), iotProperties.getAccessSecret());
        IAcsClient client = new DefaultAcsClient(profile);
        SetDevicePropertyRequest request = new SetDevicePropertyRequest();
        request.setIotInstanceId("iot-010a0axp");
        request.setDeviceName(snCode);
        request.setProductKey(productKey);
        request.setItems(JsonUtils.objectToJson(items));
        log.info("SetDevicePropertyRequest,deviceName:{},productKey:{},items:{}", snCode, productKey, request.getItems());
        try {
            SetDevicePropertyResponse response = client.getAcsResponse(request);
            log.info("SetDevicePropertyResponse:{}", JsonUtils.objectToJson(response));
            if (response.getSuccess()) {
                return true;
            }
            log.error("setDevicePropertyStatus error snCode:{},productKey:{},items:{},errorCode:{},errorMessage:{}",
                    snCode, productKey, items, response.getCode(), response.getErrorMessage());
        } catch (ClientException e) {
            log.error("setDevicePropertyStatus error snCode:{},productKey:{},items:{}", snCode, productKey, items, e);
        }
        return false;
    }

    /**
     * 批量设置设备属性
     *
     * @param deviceNameList    sn列表
     * @param productKey        产品key
     * @param items             参数
     * @return  boole
     */
    public boolean batchSetDeviceProperty(String productKey, Map<String, Object> items,List<String> deviceNameList){
        try {
            com.aliyun.iot20180120.Client client = createClient(iotProperties.getAccessKey(), iotProperties.getAccessSecret());
            SetDevicesPropertyRequest setDevicesPropertyRequest = new SetDevicesPropertyRequest()
                    .setIotInstanceId("iot-010a0axp")
                    .setProductKey(productKey)
                    .setItems(JsonUtils.objectToJson(items))
                    .setDeviceName(deviceNameList);
            // 复制代码运行请自行打印 API 的返回值
            log.info("批量设置设备属性请求参数:{}",JSON.toJSONString(setDevicesPropertyRequest));
            SetDevicesPropertyResponse setDevicesPropertyResponse = client.setDevicesProperty(setDevicesPropertyRequest);
            if(setDevicesPropertyResponse.getBody().getSuccess()){
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }



    /**
     * 使用AK&SK初始化账号Client
     *
     * @param accessKeyId
     * @param accessKeySecret
     * @return Client
     * @throws Exception
     */
    public static com.aliyun.iot20180120.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
        Config config = new Config()
                // 您的AccessKey ID
                .setAccessKeyId(accessKeyId)
                // 您的AccessKey Secret
                .setAccessKeySecret(accessKeySecret);
        // 访问的域名
        config.endpoint = "iot.cn-beijing.aliyuncs.com";
        return new com.aliyun.iot20180120.Client(config);
    }


    /**
     * 查询设备上报过的OTA模块版本列表（查询当前设备的版本）
     *
     * @return
     */
    public ListOTAModuleVersionsByDeviceResponseBody.ListOTAModuleVersionsByDeviceResponseBodyData selectDeviceOtaModleList(String productKey, String deviceName) throws Exception {
        try {
            com.aliyun.iot20180120.Client client = createClient(iotProperties.getAccessKey(), iotProperties.getAccessSecret());
            ListOTAModuleVersionsByDeviceRequest listOTAModuleVersionsByDeviceRequest = new ListOTAModuleVersionsByDeviceRequest()
                    .setIotInstanceId("iot-010a0axp")
//                .setProductKey("g2nfzaTStNQ")
//                .setDeviceName("A4E57CDAEA98")
                    .setProductKey(productKey)
                    .setDeviceName(deviceName)
                    .setPageSize(200)
                    .setCurrentPage(1);
            // 复制代码运行请自行打印 API 的返回值
            ListOTAModuleVersionsByDeviceResponse response = client.listOTAModuleVersionsByDevice(listOTAModuleVersionsByDeviceRequest);
            log.info("ListOTAModuleVersionsByDeviceResponse {}", response);
            if (response.getBody().getSuccess()) {
                return response.getBody().getData();
            }
        } catch (Exception e) {
            log.error("ListOTAModuleVersionsByDeviceResponse ERROR {}", e.getMessage());
        }
        return null;
    }

    /**
     * 查询固件列表(版本列表)
     *
     * @param productKey  产品Key
     * @param destVersion 设备的当前版本，从上报过的OTA模块版本列表获取
     * @return
     */
    public ListOTAFirmwareResponseBody.ListOTAFirmwareResponseBodyFirmwareInfo selectOTAFirmwareList(String productKey, String destVersion) {
        try {
            com.aliyun.iot20180120.Client client = createClient(iotProperties.getAccessKey(), iotProperties.getAccessSecret());
            ListOTAFirmwareRequest listOTAFirmwareRequest = new ListOTAFirmwareRequest()
                    .setIotInstanceId("iot-010a0axp")
                    .setProductKey(productKey)
                    .setDestVersion(destVersion)
                    .setPageSize(50)
                    .setCurrentPage(1);
            // 复制代码运行请自行打印 API 的返回值
            ListOTAFirmwareResponse response = client.listOTAFirmware(listOTAFirmwareRequest);
            log.info("ListOTAFirmwareResponse {}", response);
            if (response.getBody().getSuccess()) {
                return response.getBody().getFirmwareInfo();
            }
        } catch (Exception e) {
            log.error("ListOTAFirmwareResponse ERROR {}", e.getMessage());
        }
        return null;
    }


    /**
     * 创建静态升级批次
     *
     * @param productKey     产品Key
     * @param firmwareId     升级包ID（从查询固件列表中获取）
     * @param deviceNameList 设备列表
     * @return
     */
    public CreateOTAStaticUpgradeJobResponseBody.CreateOTAStaticUpgradeJobResponseBodyData createOTAStaticUpgradeJob(String productKey, String firmwareId, List<String> deviceNameList) {
        try {
            com.aliyun.iot20180120.Client client = createClient(iotProperties.getAccessKey(), iotProperties.getAccessSecret());
            CreateOTAStaticUpgradeJobRequest createOTAStaticUpgradeJobRequest = new CreateOTAStaticUpgradeJobRequest()
                    .setIotInstanceId("iot-010a0axp")
                    .setFirmwareId(firmwareId)
                    .setProductKey(productKey)
                    .setTargetSelection("SPECIFIC")
                    .setTimeoutInMinutes(15)
                    .setRetryCount(5)
                    .setTargetDeviceName(deviceNameList);
            // 复制代码运行请自行打印 API 的返回值
            CreateOTAStaticUpgradeJobResponse otaStaticUpgradeJob = client.createOTAStaticUpgradeJob(createOTAStaticUpgradeJobRequest);
            if (otaStaticUpgradeJob.getBody().getSuccess()) {
                return otaStaticUpgradeJob.getBody().getData();
            }
        } catch (Exception e) {
            log.error("CreateOTAStaticUpgradeJobResponse ERROR {}", e.getMessage());
        }
        return null;
    }


    /**
     * 查询指定升级批次的详情
     *
     * @param jobId 任务ID
     */
    public QueryOTAJobResponseBody.QueryOTAJobResponseBodyData selectOTAJobRequest(String jobId) {
        try {
            com.aliyun.iot20180120.Client client = createClient(iotProperties.getAccessKey(), iotProperties.getAccessSecret());
            QueryOTAJobRequest queryOTAJobRequest = new QueryOTAJobRequest()
                    .setJobId(jobId)
                    .setIotInstanceId("iot-010a0axp");
            // 复制代码运行请自行打印 API 的返回值
            QueryOTAJobResponse queryOTAJobResponse = client.queryOTAJob(queryOTAJobRequest);
            if (queryOTAJobResponse.getBody().getSuccess()) {
                return queryOTAJobResponse.getBody().getData();
            }
        } catch (Exception e) {
            log.error("QueryOTAJobResponse ERROR {}", e.getMessage());
        }
        return null;
    }

    /**
     * 查询指定升级批次下的设备升级作业列表
     *
     * @param jobId          任务ID
     * @return
     */
    public ListOTATaskByJobResponseBody.ListOTATaskByJobResponseBodyData selectOTATaskByJobList(String jobId) {
        try {
            com.aliyun.iot20180120.Client client = createClient(iotProperties.getAccessKey(), iotProperties.getAccessSecret());
            ListOTATaskByJobRequest listOTATaskByJobRequest = new ListOTATaskByJobRequest()
                    .setIotInstanceId("iot-010a0axp")
                    .setJobId(jobId)
                    .setPageSize(100)
                    .setCurrentPage(1);
            // 复制代码运行请自行打印 API 的返回值
            ListOTATaskByJobResponse listOTATaskByJobResponse = client.listOTATaskByJob(listOTATaskByJobRequest);
            if (listOTATaskByJobResponse.getBody().getSuccess()) {
                return listOTATaskByJobResponse.getBody().getData();
            }
        } catch (Exception e) {
            log.error("ListOTATaskByJobResponse ERROR {}", e.getMessage());
        }
        return null;
    }


}
